#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - Web Service - Web Service daemon
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import os.path
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../errorlog"))
import errorlog
import commands
import time
from signal import SIGTERM
import daemon
from SimpleXMLRPCServer import SimpleXMLRPCServer
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../core"))
import configuration
import services

# File to save process ID
DAEMON_PID_FILE = "/tmp/predesys-server-webservice.pid"
    
# Log Server daemon path
LOG_SERVER = os.path.join(DIR, "../errorlog/logserver.py")

# Service method
def get_services():
    """Gets all Predesys 'callable-user' services. This is a web service method.
    @return: List of services
    @rtype: C{list}"""
    return services.get_enabled_services_by_type("callable-user")
    
# Service method
def get_service_description(serviceId):
    """Gets the description of one of the Predesys services. This is a web service method.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @return: Description
    @rtype: C{str}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "":
        raise Exception("Service ID must be a not null and not empty string")
    if not services.is_service(serviceId):
        raise Exception("Service ID not valid")
    
    service = services.get_service_data(serviceId)
    serviceType = service.get_type()
    
    if serviceType == None:
        raise Exception("Service ID not valid")
    else:
        serviceTypeId = serviceType.get_id()
        if serviceTypeId != "callable-user":
            raise Exception("Service ID not valid")
            
    if not service.is_enabled():
        raise Exception("Service ID not valid")
    
    return "<description><name>%s</name><authenticated>%d</authenticated></description>" % (service.get_name(), int(service.is_authenticated()))

# Service method
def run_callable_service(serviceId, args):
    """Runs a callable service that does not require user authentication. This is a web service method.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @param args: Service input arguments
    @type args: C{list}
    @return: Service output
    @rtype: C{str}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "":
        raise Exception("Service ID must be a not null and not empty string")
    if args != None and type(args) != list:
        raise Exception("Service arguments must be null or a string array")
    if not services.is_service(serviceId):
        raise Exception("Service ID not valid")
    
    service = services.get_service_data(serviceId)
    serviceType = service.get_type()
    
    if serviceType == None:
        raise Exception("Service ID not valid")
    else:
        serviceTypeId = serviceType.get_id()
        if serviceTypeId != "callable-system" and serviceTypeId != "callable-user":
            raise Exception("Service ID not valid")
    
    if not service.is_enabled():
        raise Exception("Service ID not valid")
        
    result = None

    try:
        result = services.run_callable_service(serviceId, args)
    except:
        raise Exception("Error running service")
    
    if result == None:
        result = ""
        
    return result
    
# Service method
def run_callable_authenticated_service(serviceId, args, userId, userPassword):
    """Runs a callable service that requires user authentication. This is a web service method.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @param args: Service input arguments
    @type args: C{list}
    @param userId: User ID
    @type userId: C{str}
    @param userPassword: User password
    @type userPassword: C{str}
    @return: Service output
    @rtype: C{str}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "":
        raise Exception("Service ID must be a not null and not empty string")
    if args != None and type(args) != list:
        raise Exception("Service arguments must be null or a string array")
    if userId == None or (type(userId) != str and type(userId) != unicode) or userId == "":
        raise Exception("User ID must be a not null and not empty string")
    if userPassword == None or (type(userPassword) != str and type(userPassword) != unicode) or userPassword == "":
        raise Exception("User password must be a not null and not empty string")
    if not services.is_service(serviceId):
        raise Exception("Service ID not valid")
    
    service = services.get_service_data(serviceId)
    serviceType = service.get_type()
    
    if serviceType == None:
        raise Exception("Service ID not valid")
    else:
        serviceTypeId = serviceType.get_id()
        if serviceTypeId != "callable-system" and serviceTypeId != "callable-user":
            raise Exception("Service ID not valid")
    
    if not service.is_enabled():
        raise Exception("Service ID not valid")
        
    result = None

    try:
        result = services.run_callable_service(serviceId, args, userId, userPassword)
    except:
        raise Exception("Error running service")
     
    if result == None:
        result = ""
        
    return result
    
class PredesysServerWebServiceProxy(daemon.Daemon):
    """Predesys Server Web Service daemon.   
    It does all the work of the proxy."""
    def __init__(self):
        daemon.Daemon.__init__(self, pidfile=DAEMON_PID_FILE)
              
    def run(self):
        """Does the daemon work.
        It keeps running the web service.""" 
        try:
            commands.getoutput("python %s start" % LOG_SERVER) # Starts log server
            self.__load_configuration()
                    
            server = SimpleXMLRPCServer((self.config.get_webservice_host(), self.config.get_webservice_port()))
            server.register_function(get_services)
            server.register_function(get_service_description)
            server.register_function(run_callable_service)
            server.register_function(run_callable_authenticated_service)

            # Run the server's main loop
            server.serve_forever()
        except Exception as exc:
            errorlog.log_exception(exc.args[0], "predesys-server.webservice.predesys-server-webservice.PredesysServerWebServiceProxy.run")
        
    def stop(self):
        """Stops the web service."""
        commands.getoutput("python %s stop" % LOG_SERVER) # Stops log server
        daemon.Daemon.stop(self)
    
    def __load_configuration(self):
        """Loads configuration from CONFIG_FILE_1 file or CONFIG_FILE_2 file.  
        If an error occurs, it sets the default configuration."""
        self.config = configuration.load_configuration()
        
if __name__ == "__main__":
    if len(sys.argv) == 2:
        if sys.argv[1] == "start":
            PredesysServerWebServiceProxy().start()
        elif sys.argv[1] == "restart":
            PredesysServerWebServiceProxy().restart()
        elif sys.argv[1] == "stop":
            PredesysServerWebServiceProxy().stop()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "Usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)
